package com.klun.concTrueWar.twelve;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 12 -5 测试BoundedBuffer 的生产者-消费者程序
 */
public class PutTakeTest {
    private static final ExecutorService pool = Executors.newCachedThreadPool();
    private final AtomicInteger putSum = new AtomicInteger(0);
    private final AtomicInteger takeSum = new AtomicInteger(0);
    private final CyclicBarrier barrier;
    private final BoundedBuffer<Integer> bb;
    // ???? nPairs：多少对消费者和生产者
    private final int nThrials,nPairs;

    public static void main(String[] args) {
        new PutTakeTest(10,10,100).test();
        pool.shutdown();
    }

    public PutTakeTest(int capacity, int nPairs, int nThrials) {
        this.bb = new BoundedBuffer<Integer>(capacity);
        this.barrier = new CyclicBarrier(nPairs*2+1);
        this.nThrials = nThrials;
        this.nPairs = nPairs;
    }
    void test(){
        try{
            for (int i = 0; i < nPairs; i++) {
                pool.execute(new Producer());
                pool.execute(new Consumer());
                //System.out.println("zero ----Test().for()---当前等待线程数量："+barrier.getNumberWaiting());
            }
            Thread.sleep(1000);
            System.out.println("one ----Test()---当前等待线程数量："+barrier.getNumberWaiting()+" 需要等待的数量："+(nPairs*2+1));
            barrier.await();// 等待所有的线程就绪
            Thread.sleep(1000);
            System.out.println("two ----Test()---当前等待线程数量："+barrier.getNumberWaiting());
            barrier.await();// 等待所有的线程执行完成
            // 断言相等？？
            assertEquals(putSum.get(),takeSum.get());


            // 插入顺序验证
            long  sumPut = 0;
            for (int i = 0; i < ConsumerPut.size(); i++) {
                Integer integer = ConsumerPut.get(i);
                sumPut += integer;
                //System.out.print(ConsumerPut.get(i));
            }
            System.out.println();
            long  sumTake = 0;
            for (int i = 0; i < ConsumerTake.size(); i++) {
                sumTake += ConsumerTake.get(i);
                //System.out.print(ConsumerTake.get(i));
            }
            System.out.println();
            System.out.println("sumPut = "+sumPut);
            System.out.println("sumPut = "+sumTake);

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

    /**
     * 自己猜测 对比两个是否相等
     * @param i
     * @param i1
     */
    private void assertEquals(int i, int i1) {
        System.out.println("最终结果：putSum = "+i+", takeSum = "+i1);
    }
    List<Integer> ConsumerPut = new ArrayList<Integer>();
    class Producer implements Runnable{
        @Override
        public void run() {
            try{
                int seed = (this.hashCode() ^ (int)System.nanoTime());
                int sum = 0;
                // 循环栅栏 等待到期
                //System.out.println("one ----Producer---当前等待线程数量："+barrier.getNumberWaiting());
                barrier.await();
                for (int i = nThrials; i > 0 ; --i) {
                    bb.put(seed);
                    ConsumerPut.add(seed);
                    sum += seed;
                    seed = xorShift(seed);
                }
                int getandAdd = putSum.getAndAdd(sum);
                System.out.println("----Producer---当前线程"+Thread.currentThread().getName()+"获取值："+getandAdd+"更新值"+sum);
                // 等待完成
                //System.out.println("two ----Producer---当前等待线程数量："+barrier.getNumberWaiting());
                barrier.await();

            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 自己猜测 异或自己 再次随便给了一个数
     * @param seed
     * @return
     */
    private int xorShift(int seed) {
        return seed ^ 0xffff;
    }
    List<Integer> ConsumerTake = new ArrayList<Integer>();
    class Consumer implements Runnable{

        @Override
        public void run() {
            try{
                // 先等待有足够的数量
                barrier.await();
                int sum = 0;
                for (int i = nThrials; i > 0 ; --i) {
                    Integer take = bb.take();
                    ConsumerTake.add(take);
                    sum += take;
                }
                int getandAdd = takeSum.getAndAdd(sum);
                // System.out.println("----Consumer---当前线程"+Thread.currentThread().getName()+"获取值："+getandAdd+"更新值"+sum);
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}
